package com.codeoss.framework.view.service.impl;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;

import com.codeoss.framework.context.YunContext;
import com.codeoss.framework.data.metadata.Column;
import com.codeoss.framework.data.metadata.Table;
import com.codeoss.framework.data.store.ITableStore;
import com.codeoss.framework.expression.Expression;
import com.codeoss.framework.expression.IScriptService;
import com.codeoss.framework.expression.IScriptServiceStore;
import com.codeoss.framework.expression.JavaScriptScriptService;
import com.codeoss.framework.util.StringUtils;
import com.codeoss.framework.view.component.Component;
import com.codeoss.framework.view.component.IDataBinding;
import com.codeoss.framework.view.component.IVarName;
import com.codeoss.framework.view.component.Page;
import com.codeoss.framework.view.component.chart.AbstractChart;
import com.codeoss.framework.view.component.chart.ChartDataItemDef;
import com.codeoss.framework.view.component.chart.IndicatorTable;
import com.codeoss.framework.view.datasource.DataSourceConfig;
import com.codeoss.framework.view.service.IVariableService;

@Service("indicatortableComponentService")
public class IndicatorTableComponentService extends AbstractChartComponentService {
	@Autowired
	private IScriptServiceStore scriptServiceStore;
	@Autowired
	private JdbcTemplate jdbcTemplate;
	@Autowired
	private IVariableService variableService;
	@Autowired
	private ITableStore tableStore;
	@Autowired
	private JavaScriptScriptService javaScriptScriptService;

	@Override
	public void getChartData(YunContext yunContext, Component component) {
		IndicatorTable indicatorTable = (IndicatorTable) component;
		List<ChartDataItemDef> dimensionList = indicatorTable.getDimensionList();
		List<ChartDataItemDef> measureList = indicatorTable.getMeasureList();
		if (dimensionList.size() > 0 && measureList.size() > 0) {
			super.getChartData(yunContext, component);
			return;
		}
		AbstractChart abstractChart = (AbstractChart) component;
		Page page = yunContext.getPage();
		DataSourceConfig dataSourceConfig = page.getDataSourceConfigById(abstractChart.getDataSource());
		StringBuilder sqlBuilder = new StringBuilder();
		sqlBuilder.append("SELECT * FROM ");
		sqlBuilder.append(dataSourceConfig.getTableName());
		Expression whereClauseExpression = dataSourceConfig.getWhereClause();
		boolean hasWhere = false;
		if (whereClauseExpression != null) {
			IScriptService scriptService = scriptServiceStore.getScriptService(whereClauseExpression);
			String whereClause = (String) scriptService.eval(whereClauseExpression.getScript(),
					yunContext.getVarValueMap());
			if (!StringUtils.isEmpty(whereClause)) {
				sqlBuilder.append(" WHERE ");
				sqlBuilder.append(whereClause);
				hasWhere = true;
			}
		}
		whereClauseExpression = abstractChart.getWhereClauseExpression();
		if (whereClauseExpression != null) {
			IScriptService scriptService = scriptServiceStore.getScriptService(whereClauseExpression);
			String whereClause = (String) scriptService.eval(whereClauseExpression.getScript(),
					yunContext.getVarValueMap());
			if (!StringUtils.isEmpty(whereClause)) {
				if (!hasWhere) {
					sqlBuilder.append(" WHERE ");
				} else {
					sqlBuilder.append(" AND ");
				}
				sqlBuilder.append(whereClause);
				hasWhere = true;
			}
		}
		Object para[] = new Object[] {};
		List<IDataBinding> searchDataBindingList = page.getAttribute("key_search_field_list");
		if (searchDataBindingList != null) {
			List<Object> valueList = new ArrayList<Object>();
			for (int i = 0; i < searchDataBindingList.size(); i++) {
				IDataBinding dataBinding = searchDataBindingList.get(i);
				Object value = variableService.getVariableValue(yunContext, ((IVarName) dataBinding).getVarName());
				if (value != null) {
					if (!hasWhere) {
						sqlBuilder.append(" WHERE 1=1 ");
						hasWhere = true;
					}
					valueList.add(value);
					String fieldInfos = page.getPageContext("field_" + dataBinding.getDataField());
					if (!StringUtils.isEmpty(fieldInfos)) {
						String fieldInfoArray[] = fieldInfos.split("[|]");
						sqlBuilder.append(" AND ").append(fieldInfoArray[0]).append(fieldInfoArray[1]).append("?");
					} else {
						sqlBuilder.append(" AND ").append(dataBinding.getDataField()).append("=?");
					}
				}
			}
			if (valueList.size() > 0) {
				para = valueList.toArray();
			}
		}
		List<Map<String, Object>> mapList = jdbcTemplate.queryForList(sqlBuilder.toString(), para);
		Table table = tableStore.get(dataSourceConfig.getTableName());
		List<Column> columnList = table.getAllColumnList();
		for (int i = 0; i < mapList.size(); i++) {
			Map<String, Object> dataMap = mapList.get(i);
			for (Column column : columnList) {
				if (!column.isStoreColumn()) {
					String defaultValueExpression = column.getDefaultValueExpression();
					if (!StringUtils.isEmpty(defaultValueExpression)) {
						Object value = javaScriptScriptService.eval(defaultValueExpression, dataMap);
						dataMap.put(column.getColumnName(), value);
					}
				}
			}
		}

		BigDecimal total = new BigDecimal(0);
		long length = 0;
		String measureField = measureList.get(0).getField();
		String aggregateType = measureList.get(0).getAggregateType();
		for (int i = 0; i < mapList.size(); i++) {
			Map<String, Object> map = mapList.get(i);
			Object measureValue = map.get(measureField);
			if ("sum".equals(aggregateType)) {
				total = total.add(new BigDecimal(measureValue + ""));
			} else if ("average".equals(aggregateType)) {
				total = total.add(new BigDecimal(measureValue + ""));
				length++;
			} else if ("count".equals(aggregateType)) {
				length++;
			}
		}
		if ("sum".equals(aggregateType)) {
			yunContext.setAttribute(component.getId() + "_chartdata", total);
		} else if ("average".equals(aggregateType)) {
			if(length==0) {
				yunContext.setAttribute(component.getId() + "_chartdata", new BigDecimal(0));
			}else {
				total = total.divide(new BigDecimal(length + ""),2,BigDecimal.ROUND_HALF_UP);
				yunContext.setAttribute(component.getId() + "_chartdata", total);
			}
		} else if ("count".equals(aggregateType)) {
			yunContext.setAttribute(component.getId() + "_chartdata", new BigDecimal(length));
		}
		
	}
}
